﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace TheOliver.Controls
{

	/// <summary>
	/// Drags an element around under the mouse, when the mouse is clicked.
	/// </summary>
	public class DragMoveBehavior : Behavior<FrameworkElement> {

		private bool isMouseCaptured = false;
		private TranslateTransform translation;
		private Point mouseDownPt;

		/// <summary>
		/// 
		/// </summary>
		public static readonly DependencyProperty BoundsProperty = DependencyProperty.Register("Bounds", typeof(Rect), typeof(DragMoveBehavior), new PropertyMetadata(null));

		/// <summary>
		/// Area constraining the drag movement. An empty rect indicates that it is unbounded.
		/// </summary>
		public Rect Bounds {
			get { return (Rect)this.GetValue(DragMoveBehavior.BoundsProperty); }
			set { this.SetValue(DragMoveBehavior.BoundsProperty, value); }
		}

		/// <summary>
		/// Hook up to the specified events on the associated object.
		/// </summary>
		protected override void OnAttached() {
			base.OnAttached();


			this.AssociatedObject.MouseLeftButtonDown += this.HandleMouseDown;
			this.AssociatedObject.MouseLeftButtonUp += this.HandleMouseUp;
			this.AssociatedObject.MouseMove += this.HandleMouseMove;
			this.AssociatedObject.LostMouseCapture += this.HandleLostCapture;

			this.translation = new TranslateTransform();
			this.AssociatedObject.RenderTransform = this.translation;
		}

		/// <summary>
		/// Cleans up when getting removed.
		/// </summary>
		protected override void OnDetaching() {
			base.OnDetaching();

			this.AssociatedObject.MouseLeftButtonDown -= this.HandleMouseDown;
			this.AssociatedObject.MouseLeftButtonUp -= this.HandleMouseUp;
			this.AssociatedObject.MouseMove -= this.HandleMouseMove;
			this.AssociatedObject.LostMouseCapture -= this.HandleLostCapture;
		}

		private void HandleMouseDown(object sender, MouseButtonEventArgs e) {
			if (this.AssociatedObject.CaptureMouse()) {
				this.isMouseCaptured = true;

				this.mouseDownPt = e.GetPosition(this.AssociatedObject);
			}
		}

		private void HandleMouseMove(object sender, MouseEventArgs e) {
			if (this.isMouseCaptured) {
				Point newPt = e.GetPosition(this.AssociatedObject);

				double newX = this.translation.X - this.mouseDownPt.X - newPt.X;
				double newY = this.translation.Y - this.mouseDownPt.Y - newPt.Y;

				if (!this.Bounds.IsEmpty) {
					if (newX < this.Bounds.Left)
						newX = this.Bounds.Left;
					else if (newX > this.Bounds.Right)
						newX = this.Bounds.Right;

					if (newY < this.Bounds.Top)
						newY = this.Bounds.Top;
					else if (newY > this.Bounds.Bottom)
						newY = this.Bounds.Bottom;
				}


				this.translation.X = newX;
				this.translation.Y = newY;
			}
		}

		private void HandleMouseUp(object sender, MouseEventArgs e) {
			this.AssociatedObject.ReleaseMouseCapture();
		}

		private void HandleLostCapture(object sender, MouseEventArgs e) {

			this.isMouseCaptured = false;
		}


	}
}
